package com.example.ktdemo.exerciseselection.selectionprogressbar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;

import androidx.annotation.Nullable;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * FileName: SelectionProgressHorizontalBarView
 * Author: lzt
 * Date: 2022/7/7 9:06
 * 禁止了硬件加速
 */
public class SelectionProVerticalBarView extends View implements SelectionProBarViewApi {
    private static final String TAG = SelectionProVerticalBarView.class.getSimpleName();
    private boolean mInit = false;
    //绘制的信息
    private SelectionProBarInfo mDrawInfo;

    //控件宽高
    private int mViewWidth, mViewHeight;
    //当前进度
    private int mCurrentProgress = 0;
    //进度条最大值
    private static final int mDurationProgress = 100;

    //绘制相关变量
    //是否绘制中
    private boolean mDrawing = false;
    //是否需要动画
    private boolean mNeedAnim = false;

    //具体动画标识------------
    //是否绘制进度条中
    private boolean mDrawingProgress = false;
    //是否绘制非默认状态下的自定义背景
    private boolean mDrawingCustomBg = false;

    //动画相关参数
    //存储所有动画的ValueAnimator方便管理
    private final ConcurrentHashMap<String, ValueAnimator> animMap = new ConcurrentHashMap<>();
    private static final String ANIM_PROGRESS_NO_SEL_INFO = "ANIM_PROGRESS_NO_SEL_INFO";
    private static final String ANIM_PROGRESS_SEL_INFO = "ANIM_PROGRESS_SEL_INFO";
    private static final String ANIM_PROGRESS_CHANGE_BG = "ANIM_PROGRESS_CHANGE_BG";
    //动画时长--这是完整动画情况下显示的时长，具体需要计算
    private static final long ANIM_TIME_SELECT_PROGRESS = 300;
    private static final long ANIM_TIME_UNSELECT = 300;
    private static final long ANIM_TIME_CHANGE_BG = 300;


    //监听事件
    private SelectionProBarListener mListener;

    //触摸相关变量
    private float mTouchX = 0;
    private float mTouchY = 0;
    private static final float mClickInterval = 5;

    //状态变量0默认状态(只有背景) 1非选中(有进度) 2选中(有进度)
    private static final int TYPE_STATUS_DEFAULT = 0;
    private static final int TYPE_STATUS_UN_SEL = 1;
    private static final int TYPE_STATUS_SEL = 2;

    //画笔
    private Paint mPaint;
    private Paint mChangeBgPaint;
    private Paint mProgressPaint;

    //高斯模糊半径
    private static final int mBlurRadius = 2;

    public int getCurrentProgress() {
        return mCurrentProgress;
    }

    public void setCurrentProgress(int mCurrentProgress) {
        this.mCurrentProgress = mCurrentProgress;
    }

    public SelectionProVerticalBarView(Context context) {
        super(context);
    }

    public SelectionProVerticalBarView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initParams();
    }

    public SelectionProVerticalBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initParams();
    }

    private void stopAnimAndRemoveCallbacks() {
        for (Map.Entry<String, ValueAnimator> entry : animMap.entrySet()) {
            entry.getValue().cancel();
        }
        animMap.clear();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return super.onTouchEvent(event);
        }
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mTouchX = event.getX();
                mTouchY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                float upX = event.getX();
                float upY = event.getY();
                float absX = Math.abs(upX - mTouchX);
                float absY = Math.abs(upY - mTouchY);
                if (absX <= mClickInterval && absY <= mClickInterval) {
                    //点击事件
                    notifyClick(upX, upY);
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDetachedFromWindow() {
        stopAnimAndRemoveCallbacks();
        super.onDetachedFromWindow();
    }

    private void startValueAnimator(ValueAnimator valueAnimator) {
        if (hadInit() && needDraw() && needAnim()) {
            valueAnimator.start();
        }
    }

    /**
     * 当前状态
     * 0默认状态(只有背景) 1非选中(有进度) 2选中(有进度)
     */
    private int getStatus() {
        if (mDrawInfo == null) {
            return 0;
        }
        return mDrawInfo.getStatus();
    }

    private void startWithAnim(SelectionProBarInfo info) {
        boolean isSelect = info.getStatus() == TYPE_STATUS_SEL;
        if (isSelect) {
            //选中--先绘制水波纹
            mDrawingCustomBg = true;
            startCustomBgSelect(info);
            postInvalidate();
            return;
        }
        boolean unSelect = info.getStatus() == TYPE_STATUS_UN_SEL;
        if (unSelect) {
            mDrawingCustomBg = true;
            startCustomBgNoSelect(info);
            postInvalidate();
            return;
        }
        //默认状态
        postInvalidate();
        Log.d(TAG, "startWithAnim no include");
    }


    /**
     * 绘制选中的背景
     */
    private void startCustomBgSelect(SelectionProBarInfo info) {
        int targetProgress = 100;
        int currentProgress = 0;
        ValueAnimator valueAnimator = animMap.get(ANIM_PROGRESS_CHANGE_BG);
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
        valueAnimator = ValueAnimator.ofInt(currentProgress, targetProgress);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration(ANIM_TIME_CHANGE_BG);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                postInvalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mDrawingProgress = true;
                startProgressSelect(info);
                postInvalidate();
            }
        });
        animMap.put(ANIM_PROGRESS_CHANGE_BG, valueAnimator);
        startValueAnimator(valueAnimator);

    }


    /**
     * 有选中的动画效果
     */
    private void startProgressSelect(SelectionProBarInfo info) {
        int targetProgress = info.getProgress();
        int currentProgress = 0;
        ValueAnimator valueAnimator = animMap.get(ANIM_PROGRESS_SEL_INFO);
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
        int interval = Math.abs(currentProgress - targetProgress);
        valueAnimator = ValueAnimator.ofInt(currentProgress, targetProgress);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration((long) (ANIM_TIME_SELECT_PROGRESS * 1.0f / mDurationProgress * interval));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                setCurrentProgress(animatedValue);
                postInvalidate();
            }
        });
        animMap.put(ANIM_PROGRESS_SEL_INFO, valueAnimator);
        startValueAnimator(valueAnimator);
    }


    /**
     * 没有选中的自定义背景
     */
    private void startCustomBgNoSelect(SelectionProBarInfo info) {
        int targetProgress = 100;
        int currentProgress = 0;
        ValueAnimator valueAnimator = animMap.get(ANIM_PROGRESS_CHANGE_BG);
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
        valueAnimator = ValueAnimator.ofInt(currentProgress, targetProgress);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration(ANIM_TIME_CHANGE_BG);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                postInvalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mDrawingProgress = true;
                startProgressNoSelect(info);
                postInvalidate();
            }
        });
        animMap.put(ANIM_PROGRESS_CHANGE_BG, valueAnimator);
        startValueAnimator(valueAnimator);
    }


    /**
     * 没选中的动画效果
     */
    private void startProgressNoSelect(SelectionProBarInfo info) {
        int targetProgress = info.getProgress();
        int currentProgress = getCurrentProgress();
        ValueAnimator valueAnimator = animMap.get(ANIM_PROGRESS_NO_SEL_INFO);
        if (valueAnimator != null) {
            valueAnimator.cancel();
        }
        int interval = Math.abs(currentProgress - targetProgress);
        valueAnimator = ValueAnimator.ofInt(currentProgress, targetProgress);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration((long) (ANIM_TIME_UNSELECT * 1.0f / mDurationProgress * interval));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                setCurrentProgress(animatedValue);
                postInvalidate();
            }
        });
        animMap.put(ANIM_PROGRESS_NO_SEL_INFO, valueAnimator);
        startValueAnimator(valueAnimator);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!hadInit()) {
            return;
        }
        if (getStatus() == TYPE_STATUS_DEFAULT) {
            drawBgInfo(canvas);
            return;
        }
        if (!needDraw()) {
            return;
        }
        if (!needAnim()) {
            drawChangeBg(canvas);
            //不需要动画，直接画进度条
            drawProgressInfo(canvas);
            return;
        }
        //绘制顺序：
        //非选中模式，进度条慢慢叠加，直到进度值
        if (mDrawingCustomBg) {
            //绘制修改后的背景
            drawChangeBg(canvas);
        }
        if (mDrawingProgress) {
            //绘制进度条
            drawProgressInfo(canvas);
        }
    }


    /**
     * 初始化参数
     */
    private void initParams() {
        //禁用硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(1);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setTextAlign(Paint.Align.LEFT);
        mPaint.setTextSize(dp2px(12));
        mChangeBgPaint = new Paint();
        mChangeBgPaint.setStyle(Paint.Style.FILL);
        mChangeBgPaint.setStrokeWidth(1);
        mChangeBgPaint.setAntiAlias(true);
        mChangeBgPaint.setDither(true);
        mChangeBgPaint.setTextAlign(Paint.Align.LEFT);
        mChangeBgPaint.setTextSize(dp2px(12));
        mProgressPaint = new Paint();
        mProgressPaint.setStyle(Paint.Style.FILL);
        mProgressPaint.setStrokeWidth(1);
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setDither(true);
        mProgressPaint.setTextAlign(Paint.Align.LEFT);
        mProgressPaint.setTextSize(dp2px(12));
    }

    private void resetParams(boolean validate) {
        mDrawing = false;
        mNeedAnim = false;
        mDrawingProgress = false;
        mDrawingCustomBg = false;
        setCurrentProgress(0);
        if (validate) {
            postInvalidate();
        }
    }

    //布尔值判断func--------------------------------------------------------------------

    /**
     * 是否初始化完成
     */
    private boolean hadInit() {
        if (!mInit || mDrawInfo == null || mPaint == null) {
            return false;
        }
        return true;
    }

    /**
     * 是否需要绘制
     */
    private boolean needDraw() {
        return mDrawing;
    }

    /**
     * 是否需要动画
     */
    private boolean needAnim() {
        return mNeedAnim;
    }

    //绘制相关func--------------------------------------------------------------------


    /**
     * 绘制背景
     */
    private void drawBgInfo(Canvas canvas) {
        //设置混合模式
        mPaint.setXfermode(null);
        mPaint.setShader(null);
        mPaint.setTypeface(Typeface.DEFAULT);
        mPaint.setAlpha(255);
        mPaint.setMaskFilter(null);
        canvas.save();

        mPaint.setMaskFilter(new BlurMaskFilter(mBlurRadius, BlurMaskFilter.Blur.INNER));
        canvas.translate(0, 0);
        //绘制背景
        int radius = dp2px(mDrawInfo.getRadius());
        mPaint.setColor(getResources().getColor(mDrawInfo.getBgColor()));
        canvas.drawRoundRect(0, 0, mViewWidth, mViewHeight, radius, radius, mPaint);
        canvas.restore();
    }

    /**
     * 绘制修改后的背景
     */
    private void drawChangeBg(Canvas canvas) {
        mChangeBgPaint.setXfermode(null);
        mChangeBgPaint.setShader(null);
        mChangeBgPaint.setTypeface(Typeface.DEFAULT);
        mChangeBgPaint.setAlpha(255);
        mChangeBgPaint.setMaskFilter(null);
        canvas.save();

        mChangeBgPaint.setMaskFilter(new BlurMaskFilter(mBlurRadius, BlurMaskFilter.Blur.INNER));
        //绘制背景
        int radius = dp2px(mDrawInfo.getRadius());
        if (getStatus() == TYPE_STATUS_SEL) {
            mChangeBgPaint.setColor(getResources().getColor(mDrawInfo.getSelectBgColor()));
        } else if (getStatus() == TYPE_STATUS_UN_SEL) {
            mChangeBgPaint.setColor(getResources().getColor(mDrawInfo.getUnSelBgColor()));
        } else if (getStatus() == TYPE_STATUS_DEFAULT) {
            mChangeBgPaint.setColor(getResources().getColor(mDrawInfo.getBgColor()));
        }
        canvas.drawRoundRect(0, 0, mViewWidth, mViewHeight, radius, radius, mChangeBgPaint);
        canvas.restore();
    }


    /**
     * 绘制进度
     */
    private void drawProgressInfo(Canvas canvas) {
        //设置混合模式
        mProgressPaint.setXfermode(null);
        mProgressPaint.setShader(null);
        mProgressPaint.setTypeface(Typeface.DEFAULT);
        mProgressPaint.setAlpha(255);
        //不需要动画
        canvas.save();

        //先剪裁出绘制区域，然后再在区域上面绘制
        int radius = dp2px(mDrawInfo.getRadius());
        RectF canvasRectF = new RectF(0, 0, mViewWidth, mViewHeight);
        Path mPath = new Path();
        mPath.addRoundRect(canvasRectF, radius, radius, Path.Direction.CW);
        canvas.clipPath(mPath);

        //绘制进度--计算x轴占比
        if (getStatus() == TYPE_STATUS_SEL) {
            mProgressPaint.setColor(getResources().getColor(mDrawInfo.getProgressSelColor()));
        } else if (getStatus() == TYPE_STATUS_UN_SEL) {
            mProgressPaint.setColor(getResources().getColor(mDrawInfo.getProgressUnSelColor()));
        }
        int progress = getCurrentProgress();
        float mDrawProgress = (mViewHeight * 1.0f / mDurationProgress) * (Math.min(progress, mDurationProgress) * 1.0f);
        RectF rectProgress = new RectF(0, mViewHeight - mDrawProgress, mViewWidth, mViewHeight);
        canvas.drawRoundRect(rectProgress, 0, 0, mProgressPaint);

        canvas.restore();
        //通知外部
        notifyProgressChange(progress, mDurationProgress);
    }


    private int dp2px(int dpValue) {
        return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
    }

    //外部调用方法---------------------------------------------------------------------------------

    @Override
    public void setProgress(SelectionProBarInfo info) {
        //view初始化后才设置
        this.setProgress(info, true);
    }

    @Override
    public void setProgress(SelectionProBarInfo info, boolean anim) {
        setProgress(info, anim,160);
    }

    @Override
    public void setProgress(SelectionProBarInfo info, boolean anim, long delay) {
        resetParams(true);
        if (info == null) {
            return;
        }
        this.postDelayed(new Runnable() {
            @Override
            public void run() {
                mDrawInfo = info;
                mViewWidth = getMeasuredWidth();
                mViewHeight = getMeasuredHeight();

                mInit = true;
                mNeedAnim = anim;
                mDrawing = true;

                if (!needAnim()) {
                    //不需要动画
                    setCurrentProgress(info.getProgress());
                    postInvalidate();
                    return;
                }
                //需要动画
                setCurrentProgress(0);
                startWithAnim(info);
            }
        }, delay);
    }


    //监听事件
    public void setSelectionProgressBarListener(SelectionProBarListener listener) {
        this.mListener = listener;
    }

    //通知进度更新
    private void notifyProgressChange(int progress, int max) {
        if (this.mListener != null) {
            this.mListener.progressChange(progress, max);
        }
    }

    private void notifyClick(float touchX, float touchY) {
        if (this.mListener != null) {
            this.mListener.click(this, touchX, touchY);
        }
    }

}
